home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / audio_output / filters.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  13KB  |  330 lines

  1. /*****************************************************************************
  2.  * filters.c : audio output filters management
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: filters.c,v 1.18 2003/03/04 03:27:40 gbazin Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  28. #include <string.h>
  29.  
  30. #include <vlc/vlc.h>
  31.  
  32. #ifdef HAVE_ALLOCA_H
  33. #   include <alloca.h>
  34. #endif
  35.  
  36. #include "audio_output.h"
  37. #include "aout_internal.h"
  38.  
  39. /*****************************************************************************
  40.  * FindFilter: find an audio filter for a specific transformation
  41.  *****************************************************************************/
  42. static aout_filter_t * FindFilter( aout_instance_t * p_aout,
  43.                              const audio_sample_format_t * p_input_format,
  44.                              const audio_sample_format_t * p_output_format )
  45. {
  46.     aout_filter_t * p_filter = vlc_object_create( p_aout,
  47.                                                   sizeof(aout_filter_t) );
  48.  
  49.     if ( p_filter == NULL ) return NULL;
  50.     vlc_object_attach( p_filter, p_aout );
  51.  
  52.     memcpy( &p_filter->input, p_input_format, sizeof(audio_sample_format_t) );
  53.     memcpy( &p_filter->output, p_output_format,
  54.             sizeof(audio_sample_format_t) );
  55.     p_filter->p_module = module_Need( p_filter, "audio filter", NULL );
  56.     if ( p_filter->p_module == NULL )
  57.     {
  58.         vlc_object_detach( p_filter );
  59.         vlc_object_destroy( p_filter );
  60.         return NULL;
  61.     }
  62.  
  63.     p_filter->b_continuity = VLC_FALSE;
  64.  
  65.     return p_filter;
  66. }
  67.  
  68. /*****************************************************************************
  69.  * SplitConversion: split a conversion in two parts
  70.  *****************************************************************************
  71.  * Returns the number of conversions required by the first part - 0 if only
  72.  * one conversion was asked.
  73.  * Beware : p_output_format can be modified during this function if the
  74.  * developer passed SplitConversion( toto, titi, titi, ... ). That is legal.
  75.  * SplitConversion( toto, titi, toto, ... ) isn't.
  76.  *****************************************************************************/
  77. static int SplitConversion( const audio_sample_format_t * p_input_format,
  78.                             const audio_sample_format_t * p_output_format,
  79.                             audio_sample_format_t * p_middle_format )
  80. {
  81.     vlc_bool_t b_format =
  82.              (p_input_format->i_format != p_output_format->i_format);
  83.     vlc_bool_t b_rate = (p_input_format->i_rate != p_output_format->i_rate);
  84.     vlc_bool_t b_channels =
  85.         (p_input_format->i_physical_channels
  86.           != p_output_format->i_physical_channels)
  87.      || (p_input_format->i_original_channels
  88.           != p_output_format->i_original_channels);
  89.     int i_nb_conversions = b_format + b_rate + b_channels;
  90.  
  91.     if ( i_nb_conversions <= 1 ) return 0;
  92.  
  93.     memcpy( p_middle_format, p_output_format, sizeof(audio_sample_format_t) );
  94.  
  95.     if ( i_nb_conversions == 2 )
  96.     {
  97.         if ( !b_format || !b_channels )
  98.         {
  99.             p_middle_format->i_rate = p_input_format->i_rate;
  100.             aout_FormatPrepare( p_middle_format );
  101.             return 1;
  102.         }
  103.  
  104.         /* !b_rate */
  105.         p_middle_format->i_physical_channels
  106.              = p_input_format->i_physical_channels;
  107.         p_middle_format->i_original_channels
  108.              = p_input_format->i_original_channels;
  109.         aout_FormatPrepare( p_middle_format );
  110.         return 1;
  111.     }
  112.  
  113.     /* i_nb_conversion == 3 */
  114.     p_middle_format->i_rate = p_input_format->i_rate;
  115.     aout_FormatPrepare( p_middle_format );
  116.     return 2;
  117. }
  118.  
  119. /*****************************************************************************
  120.  * aout_FiltersCreatePipeline: create a filters pipeline to transform a sample
  121.  *                             format to another
  122.  *****************************************************************************
  123.  * TODO : allow the user to add/remove specific filters
  124.  *****************************************************************************/
  125. int aout_FiltersCreatePipeline( aout_instance_t * p_aout,
  126.                                 aout_filter_t ** pp_filters,
  127.                                 int * pi_nb_filters,
  128.                                 const audio_sample_format_t * p_input_format,
  129.                                 const audio_sample_format_t * p_output_format )
  130. {
  131.     audio_sample_format_t temp_format;
  132.     int i_nb_conversions;
  133.  
  134.     if ( AOUT_FMTS_IDENTICAL( p_input_format, p_output_format ) )
  135.     {
  136.         msg_Dbg( p_aout, "no need for any filter" );
  137.         *pi_nb_filters = 0;
  138.         return 0;
  139.     }
  140.  
  141.     aout_FormatsPrint( p_aout, "filter(s)", p_input_format, p_output_format );
  142.  
  143.     /* Try to find a filter to do the whole conversion. */
  144.     pp_filters[0] = FindFilter( p_aout, p_input_format, p_output_format );
  145.     if ( pp_filters[0] != NULL )
  146.     {
  147.         msg_Dbg( p_aout, "found a filter for the whole conversion" );
  148.         *pi_nb_filters = 1;
  149.         return 0;
  150.     }
  151.  
  152.     /* We'll have to split the conversion. We always do the downmixing
  153.      * before the resampling, because the audio decoder can probably do it
  154.      * for us. */
  155.     i_nb_conversions = SplitConversion( p_input_format,
  156.                                         p_output_format, &temp_format );
  157.     if ( !i_nb_conversions )
  158.     {
  159.         /* There was only one conversion to do, and we already failed. */
  160.         msg_Err( p_aout, "couldn't find a filter for the conversion" );
  161.         return -1;
  162.     }
  163.  
  164.     pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
  165.     if ( pp_filters[0] == NULL && i_nb_conversions == 2 )
  166.     {
  167.         /* Try with only one conversion. */
  168.         SplitConversion( p_input_format, &temp_format, &temp_format );
  169.         pp_filters[0] = FindFilter( p_aout, p_input_format, &temp_format );
  170.     }
  171.     if ( pp_filters[0] == NULL )
  172.     {
  173.         msg_Err( p_aout,
  174.               "couldn't find a filter for the first part of the conversion" );
  175.         return -1;
  176.     }
  177.  
  178.     /* We have the first stage of the conversion. Find a filter for
  179.      * the rest. */
  180.     pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
  181.                                 p_output_format );
  182.     if ( pp_filters[1] == NULL )
  183.     {
  184.         /* Try to split the conversion. */
  185.         i_nb_conversions = SplitConversion( &pp_filters[0]->output,
  186.                                            p_output_format, &temp_format );
  187.         if ( !i_nb_conversions )
  188.         {
  189.             vlc_object_detach( pp_filters[0] );
  190.             vlc_object_destroy( pp_filters[0] );
  191.             msg_Err( p_aout,
  192.               "couldn't find a filter for the second part of the conversion" );
  193.         }
  194.         pp_filters[1] = FindFilter( p_aout, &pp_filters[0]->output,
  195.                                     &temp_format );
  196.         pp_filters[2] = FindFilter( p_aout, &temp_format,
  197.                                     p_output_format );
  198.  
  199.         if ( pp_filters[1] == NULL || pp_filters[2] == NULL )
  200.         {
  201.             vlc_object_detach( pp_filters[0] );
  202.             vlc_object_destroy( pp_filters[0] );
  203.             if ( pp_filters[1] != NULL )
  204.             {
  205.                 vlc_object_detach( pp_filters[1] );
  206.                 vlc_object_destroy( pp_filters[1] );
  207.             }
  208.             if ( pp_filters[2] != NULL )
  209.             {
  210.                 vlc_object_detach( pp_filters[2] );
  211.                 vlc_object_destroy( pp_filters[2] );
  212.             }
  213.             msg_Err( p_aout,
  214.                "couldn't find filters for the second part of the conversion" );
  215.         }
  216.         *pi_nb_filters = 3;
  217.     }
  218.     else
  219.     {
  220.         *pi_nb_filters = 2;
  221.     }
  222.  
  223.     /* We have enough filters. */
  224.     msg_Dbg( p_aout, "found %d filters for the whole conversion",
  225.              *pi_nb_filters );
  226.     return 0;
  227. }
  228.  
  229. /*****************************************************************************
  230.  * aout_FiltersDestroyPipeline: deallocate a filters pipeline
  231.  *****************************************************************************/
  232. void aout_FiltersDestroyPipeline( aout_instance_t * p_aout,
  233.                                   aout_filter_t ** pp_filters,
  234.                                   int i_nb_filters )
  235. {
  236.     int i;
  237.  
  238.     for ( i = 0; i < i_nb_filters; i++ )
  239.     {
  240.         module_Unneed( pp_filters[i], pp_filters[i]->p_module );
  241.         vlc_object_detach( pp_filters[i] );
  242.         vlc_object_destroy( pp_filters[i] );
  243.     }
  244. }
  245.  
  246. /*****************************************************************************
  247.  * aout_FiltersHintBuffers: fill in aout_alloc_t structures to optimize
  248.  *                          buffer allocations
  249.  *****************************************************************************/
  250. void aout_FiltersHintBuffers( aout_instance_t * p_aout,
  251.                               aout_filter_t ** pp_filters,
  252.                               int i_nb_filters, aout_alloc_t * p_first_alloc )
  253. {
  254.     int i;
  255.  
  256.     (void)p_aout; /* unused */
  257.  
  258.     for ( i = i_nb_filters - 1; i >= 0; i-- )
  259.     {
  260.         aout_filter_t * p_filter = pp_filters[i];
  261.  
  262.         int i_output_size = p_filter->output.i_bytes_per_frame
  263.                              * p_filter->output.i_rate
  264.                              / p_filter->output.i_frame_length;
  265.         int i_input_size = p_filter->input.i_bytes_per_frame
  266.                              * p_filter->input.i_rate
  267.                              / p_filter->input.i_frame_length;
  268.  
  269.         p_first_alloc->i_bytes_per_sec = __MAX( p_first_alloc->i_bytes_per_sec,
  270.                                                 i_output_size );
  271.  
  272.         if ( p_filter->b_in_place )
  273.         {
  274.             p_first_alloc->i_bytes_per_sec = __MAX(
  275.                                          p_first_alloc->i_bytes_per_sec,
  276.                                          i_input_size );
  277.             p_filter->output_alloc.i_alloc_type = AOUT_ALLOC_NONE;
  278.         }
  279.         else
  280.         {
  281.             /* We're gonna need a buffer allocation. */
  282.             memcpy( &p_filter->output_alloc, p_first_alloc,
  283.                     sizeof(aout_alloc_t) );
  284.             p_first_alloc->i_alloc_type = AOUT_ALLOC_STACK;
  285.             p_first_alloc->i_bytes_per_sec = i_input_size;
  286.         }
  287.     }
  288. }
  289.  
  290. /*****************************************************************************
  291.  * aout_FiltersPlay: play a buffer
  292.  *****************************************************************************/
  293. void aout_FiltersPlay( aout_instance_t * p_aout,
  294.                        aout_filter_t ** pp_filters,
  295.                        int i_nb_filters, aout_buffer_t ** pp_input_buffer )
  296. {
  297.     int i;
  298.  
  299.     for ( i = 0; i < i_nb_filters; i++ )
  300.     {
  301.         aout_filter_t * p_filter = pp_filters[i];
  302.         aout_buffer_t * p_output_buffer;
  303.  
  304.         /* Resamplers can produce slightly more samples than (i_in_nb *
  305.          * p_filter->output.i_rate / p_filter->input.i_rate) so we need
  306.          * slightly bigger buffers. */
  307.         aout_BufferAlloc( &p_filter->output_alloc,
  308.             ((mtime_t)(*pp_input_buffer)->i_nb_samples + 2)
  309.             * 1000000 / p_filter->input.i_rate,
  310.             *pp_input_buffer, p_output_buffer );
  311.         if ( p_output_buffer == NULL )
  312.         {
  313.             msg_Err( p_aout, "out of memory" );
  314.             return;
  315.         }
  316.         /* Please note that p_output_buffer->i_nb_samples & i_nb_bytes
  317.          * shall be set by the filter plug-in. */
  318.  
  319.         p_filter->pf_do_work( p_aout, p_filter, *pp_input_buffer,
  320.                               p_output_buffer );
  321.  
  322.         if ( !p_filter->b_in_place )
  323.         {
  324.             aout_BufferFree( *pp_input_buffer );
  325.             *pp_input_buffer = p_output_buffer;
  326.         }
  327.     }
  328. }
  329.  
  330.